package server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import server.config.ServerConfig;
import server.container.Context;
import server.container.Host;
import server.container.Mapper;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * Minicat的主类
 */
public class Bootstrap {

    /**定义socket监听的端口号*/
    private int port = 8080;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }


    /**
     * Minicat启动需要初始化展开的一些操作
     */
    public void start() throws Exception {


        // 定义一个线程池
        int corePoolSize = 10;
        int maximumPoolSize =50;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();


        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );


        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("=====>>>Minicat start on port：" + port);

        System.out.println("=========>>>>>>使用线程池进行多线程改造");
        /*
            多线程改造（使用线程池）
         */
        while(true) {

            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket);
            //requestProcessor.start();
            threadPoolExecutor.execute(requestProcessor);
        }



    }




    /**
     * Minicat 的程序启动入口
     * @param args
     */
    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        try {

            bootstrap.loadConfig();
            //加载资源配置，创建server
            bootstrap.initMapper();
            // 启动Minicat
            bootstrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //加载核心配置
    private void loadConfig() throws DocumentException {

        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(resourceAsStream);
        Element rootElement = document.getRootElement();


        ServerConfig serverConfig = ServerConfig.getInstance();

        Element connector = (Element) rootElement.selectSingleNode("//Connector");
        Integer port = Integer.valueOf( connector.attribute("port").getValue());

        System.out.println("load port:"+port);
        Element host = (Element) rootElement.selectSingleNode("//Host");

        String hostname = host.attribute("name").getValue();
        String appBase =   host.attribute("appBase").getValue();

        System.out.println("load hostname:"+hostname+", appBase："+appBase);
        serverConfig.setConnectPort(port);
        serverConfig.setHostname(hostname);
        serverConfig.setAppBase(appBase);


    }

    private void initMapper() throws FileNotFoundException {
        ServerConfig serverConfig = ServerConfig.getInstance();
        Mapper mapper = Mapper.getInstance();

        //1.创建host
        Host host = new Host(serverConfig.getHostname(),serverConfig.getAppBase());


        //2.扫描appBase目录,为每个目录创建为一个context,目录名称为contextPath

        File appBaseDir = new File(host.getAppBase());

        for(File dir : appBaseDir.listFiles()) {
            Context context = new Context();
            context.setContextPath(dir.getName());  //设置contextPath

             //3.解析context目录下的web.xml，加载servlet封装成wrapper
             context.load(dir.getAbsolutePath());


            //4把创建好的context添加到host里
             host.addContext("/"+context.getContextPath(),context);
        }

        //5.把host放到mapper映射里
        mapper.addHost(host.getName(),host);

    }
}
